import os
import sys
import time
import threading
import shutil
import zipfile
import py7zr
import rarfile
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import datetime
from pystray import Icon, MenuItem as item
from PIL import Image, ImageDraw

class UnzipTool:
    def __init__(self, root):
        self.root = root
        self.root.title("智能解压工具Ultra")
        self.root.geometry("1000x700")
        self.root.resizable(True, True)
        
        # 获取程序运行路径（支持打包后环境）
        self.base_path = self.get_base_path()
        
        # 设置窗口图标
        self.set_window_icon()
        
        # 配置unrar路径
        self.configure_unrar_path()
        
        # 确保中文显示正常
        if sys.platform.startswith('win'):
            self.default_font = ('SimHei', 9)
        else:
            self.default_font = ('WenQuanYi Micro Hei', 9)
        
        # 变量初始化
        self.main_dir = ""
        self.zip_files = []  # 存储扫描到的压缩文件信息
        self.scanning = False
        self.extracting = False
        self.cancel_extract = False
        self.timer_thread = None
        self.timer_running = False
        self.remaining_time = 0
        self.cache_dir = os.path.join(os.path.expanduser("~"), ".unzip_tool_cache")
        os.makedirs(self.cache_dir, exist_ok=True)
        self.current_extract_index = 0  # 当前正在解压的文件索引
        self.total_extract_count = 0    # 总解压文件数
        self.tray_icon = None  # 系统托盘图标
        self.extract_start_time = 0  # 解压开始时间
        self.elapsed_timer_running = False  # 已用时间计时器状态
        
        # 创建界面
        self.create_widgets()
        
        # 重写关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_close)
    
    def get_base_path(self):
        """获取程序运行的基础路径（兼容开发环境和打包后环境）"""
        if getattr(sys, 'frozen', False):
            # 打包后的环境（PyInstaller）
            return sys._MEIPASS
        else:
            # 开发环境
            return os.path.dirname(os.path.abspath(__file__))
    
    def set_window_icon(self):
        """设置窗口图标"""
        try:
            # 优先使用打包目录中的icon.ico
            icon_path = os.path.join(self.base_path, "icon.ico")
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
                return
                
            # 如果没有找到自定义图标，使用默认图标
            self.log("未找到自定义图标，使用默认图标")
        except Exception as e:
            self.log(f"设置图标失败: {e}")
    
    def configure_unrar_path(self):
        """配置unrar路径"""
        try:
            # 优先使用打包目录中的unrar.exe
            unrar_path = os.path.join(self.base_path, "unrar.exe")
            if os.path.exists(unrar_path):
                rarfile.UNRAR_TOOL = unrar_path
                self.log(f"已找到unrar.exe: {unrar_path}")
                return
                
            # 如果没找到，尝试系统环境变量中的unrar
            self.log("未找到打包的unrar.exe，尝试使用系统中的unrar")
            rarfile.UNRAR_TOOL = "unrar"  # 依赖系统环境变量
        except Exception as e:
            self.log(f"配置unrar失败: {e}")
    
    def create_tray_icon(self):
        """创建系统托盘图标"""
        try:
            # 尝试加载打包目录中的图标
            icon_path = os.path.join(self.base_path, "icon.ico")
            if os.path.exists(icon_path):
                image = Image.open(icon_path)
            else:
                # 如果没有自定义图标，创建一个简单的默认图标
                image = Image.new('RGB', (64, 64), color=(73, 109, 137))
                d = ImageDraw.Draw(image)
                d.text((10, 20), "UZ", fill=(255, 255, 0))
                
            # 创建菜单
            menu = (
                item('显示窗口', self.show_window),
                item('退出', self.quit_application)
            )
            
            # 确保只创建一个托盘图标实例
            if self.tray_icon:
                self.tray_icon.stop()
                
            # 创建系统托盘图标
            self.tray_icon = Icon("UnzipTool", image, "智能解压工具", menu)
            
            # 在新线程中运行托盘图标
            def run_tray():
                self.tray_icon.run()
                
            threading.Thread(target=run_tray, daemon=True).start()
        except Exception as e:
            self.log(f"创建系统托盘失败: {str(e)}")
            self.tray_icon = None
    
    def show_window(self, icon=None, item=None):
        """显示主窗口"""
        # 检查托盘图标是否存在，存在才调用hide()
        if self.tray_icon:
            try:
                self.tray_icon.hide()
            except:
                pass
        # 显示窗口并提到最前面
        self.root.deiconify()
        self.root.lift()
        self.root.focus_force()
    
    def minimize_to_tray(self):
        """最小化到系统托盘"""
        self.root.withdraw()  # 隐藏窗口
        if not self.tray_icon:
            self.create_tray_icon()
        else:
            try:
                self.tray_icon.show()
            except:
                # 尝试重新创建托盘图标
                self.create_tray_icon()
        
    def quit_application(self, icon=None, item=None):
        """退出应用程序"""
        try:
            if self.tray_icon:
                self.tray_icon.stop()
        except:
            pass
        self.elapsed_timer_running = False  # 停止已用时间计时器
        self.root.destroy()
        sys.exit(0)
    
    def on_close(self):
        """处理关闭事件"""
        # 创建确认对话框
        result = messagebox.askyesnocancel(
            "确认", 
            "请选择操作:\n- 是: 直接退出软件\n- 否: 最小化到系统托盘\n- 取消: 取消关闭",
            parent=self.root
        )
        
        if result is None:  # 取消
            return
        elif result:  # 是，直接退出
            self.quit_application()
        else:  # 否，最小化到系统托盘
            self.minimize_to_tray()
    
    def start_elapsed_timer(self):
        """启动已用时间计时器线程"""
        self.elapsed_timer_running = True
        threading.Thread(target=self.update_elapsed_time, daemon=True).start()
    
    def update_elapsed_time(self):
        """实时更新已用时间"""
        while self.elapsed_timer_running:
            if self.extracting and self.extract_start_time > 0:
                current_time = time.time()
                elapsed = current_time - self.extract_start_time
                self.root.after(0, lambda t=elapsed: self.elapsed_var.set(f"已用时间: {self.format_time(t)}"))
            time.sleep(1)  # 每秒更新一次
        
        # 解压结束后显示最终时间
        if self.extract_start_time > 0:
            final_time = time.time() - self.extract_start_time
            self.root.after(0, lambda t=final_time: self.elapsed_var.set(f"已用时间: {self.format_time(t)}"))
        
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 目录选择区域
        dir_frame = ttk.LabelFrame(main_frame, text="目录设置", padding="5")
        dir_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(dir_frame, text="主目录:").pack(side=tk.LEFT, padx=5)
        self.dir_var = tk.StringVar()
        dir_entry = ttk.Entry(dir_frame, textvariable=self.dir_var, width=50)
        dir_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
        
        browse_btn = ttk.Button(dir_frame, text="浏览", command=self.browse_dir)
        browse_btn.pack(side=tk.LEFT, padx=5)
        
        scan_btn = ttk.Button(dir_frame, text="扫描压缩包", command=self.start_scan)
        scan_btn.pack(side=tk.LEFT, padx=5)
        
        # 扫描深度设置
        depth_frame = ttk.Frame(dir_frame)
        depth_frame.pack(side=tk.LEFT, padx=5)
        ttk.Label(depth_frame, text="扫描深度:").pack(side=tk.LEFT)
        self.depth_var = tk.IntVar(value=5)
        depth_spin = ttk.Spinbox(depth_frame, from_=1, to=10, textvariable=self.depth_var, width=5)
        depth_spin.pack(side=tk.LEFT)
        
        # 压缩包列表区域
        list_frame = ttk.LabelFrame(main_frame, text="压缩包列表", padding="5")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 列表上方信息
        info_frame = ttk.Frame(list_frame)
        info_frame.pack(fill=tk.X, pady=5)
        
        self.total_count_var = tk.StringVar(value="找到压缩包: 0 个")
        ttk.Label(info_frame, textvariable=self.total_count_var).pack(side=tk.LEFT, padx=10)
        
        self.total_size_var = tk.StringVar(value="总大小: 0 MB")
        ttk.Label(info_frame, textvariable=self.total_size_var).pack(side=tk.LEFT, padx=10)
        
        # 创建列表
        columns = ("select", "name", "size", "path")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="headings")
        
        self.tree.heading("select", text="选择")
        self.tree.heading("name", text="文件名")
        self.tree.heading("size", text="大小")
        self.tree.heading("path", text="路径")
        
        self.tree.column("select", width=50, anchor=tk.CENTER)
        self.tree.column("name", width=200, anchor=tk.W)
        self.tree.column("size", width=100, anchor=tk.E)
        self.tree.column("path", width=500, anchor=tk.W)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscroll=scrollbar.set)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.tree.pack(fill=tk.BOTH, expand=True)
        
        # 绑定双击事件
        self.tree.bind("<Double-1>", self.copy_path)
        
        # 选项设置区域
        options_frame = ttk.LabelFrame(main_frame, text="解压选项", padding="5")
        options_frame.pack(fill=tk.X, pady=5)
        
        # 添加全选和取消全选按钮
        select_all_btn = ttk.Button(options_frame, text="全选", command=self.select_all)
        select_all_btn.pack(side=tk.LEFT, padx=10)
        
        deselect_all_btn = ttk.Button(options_frame, text="取消全选", command=self.deselect_all)
        deselect_all_btn.pack(side=tk.LEFT, padx=10)
        
        self.skip_errors_var = tk.BooleanVar(value=True)
        skip_errors_check = ttk.Checkbutton(options_frame, text="遇到错误自动跳过", variable=self.skip_errors_var)
        skip_errors_check.pack(side=tk.LEFT, padx=10)
        
        self.delete_after_var = tk.BooleanVar(value=True)
        delete_after_check = ttk.Checkbutton(options_frame, text="解压完成后删除原压缩包", variable=self.delete_after_var)
        delete_after_check.pack(side=tk.LEFT, padx=10)
        
        # 定时任务区域
        timer_frame = ttk.LabelFrame(main_frame, text="定时任务", padding="5")
        timer_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(timer_frame, text="设置时间 (HH:MM:SS):").pack(side=tk.LEFT, padx=5)
        self.timer_var = tk.StringVar(value="00:00:00")
        timer_entry = ttk.Entry(timer_frame, textvariable=self.timer_var, width=10)
        timer_entry.pack(side=tk.LEFT, padx=5)
        
        self.set_timer_btn = ttk.Button(timer_frame, text="设置定时", command=self.set_timer)
        self.set_timer_btn.pack(side=tk.LEFT, padx=5)
        
        self.cancel_timer_btn = ttk.Button(timer_frame, text="取消定时", command=self.cancel_timer, state=tk.DISABLED)
        self.cancel_timer_btn.pack(side=tk.LEFT, padx=5)
        
        self.timer_display_var = tk.StringVar(value="定时状态: 未设置")
        ttk.Label(timer_frame, textvariable=self.timer_display_var).pack(side=tk.LEFT, padx=20)
        
        # 进度显示区域
        progress_frame = ttk.LabelFrame(main_frame, text="解压进度", padding="5")
        progress_frame.pack(fill=tk.X, pady=5)
        
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, length=100)
        self.progress_bar.pack(fill=tk.X, pady=5)
        
        progress_info_frame = ttk.Frame(progress_frame)
        progress_info_frame.pack(fill=tk.X)
        
        # 解压计数显示
        self.extract_count_var = tk.StringVar(value="正在解压: 0/0")
        ttk.Label(progress_info_frame, textvariable=self.extract_count_var).pack(side=tk.LEFT, padx=10)
        
        self.progress_text_var = tk.StringVar(value="等待开始...")
        ttk.Label(progress_info_frame, textvariable=self.progress_text_var).pack(side=tk.LEFT, padx=10)
        
        self.speed_var = tk.StringVar(value="速度: -- MB/s")
        ttk.Label(progress_info_frame, textvariable=self.speed_var).pack(side=tk.LEFT, padx=20)
        
        self.eta_var = tk.StringVar(value="剩余时间: --:--:--")
        ttk.Label(progress_info_frame, textvariable=self.eta_var).pack(side=tk.LEFT, padx=20)
        
        # 添加解压计时显示，放在剩余时间后面
        self.elapsed_var = tk.StringVar(value="已用时间: --:--:--")
        ttk.Label(progress_info_frame, textvariable=self.elapsed_var).pack(side=tk.LEFT, padx=20)
        
        # 将开始解压和取消解压按钮放到进度条右边
        self.start_btn = ttk.Button(progress_info_frame, text="开始解压", command=self.start_extract)
        self.start_btn.pack(side=tk.RIGHT, padx=10)
        
        self.cancel_btn = ttk.Button(progress_info_frame, text="取消解压", command=self.cancel_extraction, state=tk.DISABLED)
        self.cancel_btn.pack(side=tk.RIGHT, padx=10)
        
        # 日志区域
        log_frame = ttk.LabelFrame(main_frame, text="解压日志", padding="5")
        log_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        self.log_text = tk.Text(log_frame, height=10, wrap=tk.WORD, font=self.default_font)
        self.log_text.pack(fill=tk.BOTH, expand=True)
        self.log_text.config(state=tk.DISABLED)
        
        # 添加滚动条
        log_scrollbar = ttk.Scrollbar(self.log_text, orient=tk.VERTICAL, command=self.log_text.yview)
        log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.configure(yscroll=log_scrollbar.set)
    
    # 全选功能
    def select_all(self):
        for i in range(len(self.zip_files)):
            self.zip_files[i]['selected'] = True
            item = self.tree.get_children()[i]
            self.tree.set(item, 0, "✓")
    
    # 取消全选功能
    def deselect_all(self):
        for i in range(len(self.zip_files)):
            self.zip_files[i]['selected'] = False
            item = self.tree.get_children()[i]
            self.tree.set(item, 0, "")
        
    def browse_dir(self):
        dir_path = filedialog.askdirectory()
        if dir_path:
            self.dir_var.set(dir_path)
            self.main_dir = dir_path
            
    def start_scan(self):
        if not self.dir_var.get():
            messagebox.showwarning("警告", "请先选择主目录")
            return
            
        self.main_dir = self.dir_var.get()
        if not os.path.exists(self.main_dir):
            messagebox.showerror("错误", "所选目录不存在")
            return
            
        # 清空之前的列表
        for item in self.tree.get_children():
            self.tree.delete(item)
        self.zip_files = []
        
        self.log("开始扫描压缩包...")
        self.scanning = True
        # 在新线程中执行扫描，避免UI卡顿
        threading.Thread(target=self.scan_zip_files, daemon=True).start()
        
    def scan_zip_files(self):
        depth = self.depth_var.get()
        self._scan_directory(self.main_dir, 0, depth)
        
        # 更新UI显示
        self.root.after(0, self.update_zip_list)
        self.scanning = False
        self.log(f"扫描完成，共找到 {len(self.zip_files)} 个压缩包")
        
    def _scan_directory(self, current_dir, current_depth, max_depth):
        if current_depth > max_depth or not self.scanning:
            return
            
        try:
            for entry in os.scandir(current_dir):
                if not self.scanning:  # 检查是否需要停止扫描
                    return
                    
                if entry.is_dir(follow_symlinks=False):
                    self._scan_directory(entry.path, current_depth + 1, max_depth)
                elif entry.is_file():
                    filename = entry.name.lower()
                    if filename.endswith(('.zip', '.7z', '.rar')):
                        # 获取文件大小
                        try:
                            file_size = entry.stat().st_size
                            self.zip_files.append({
                                'name': entry.name,
                                'path': entry.path,
                                'size': file_size,
                                'selected': True
                            })
                        except Exception as e:
                            self.log(f"无法获取文件信息: {entry.path}, 错误: {str(e)}")
        except Exception as e:
            self.log(f"扫描目录错误: {current_dir}, 错误: {str(e)}")
            
    def update_zip_list(self):
        # 清空现有列表
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 添加新内容
        total_size = 0
        for i, zip_file in enumerate(self.zip_files):
            size_str = self.format_size(zip_file['size'])
            self.tree.insert("", tk.END, values=(
                "✓" if zip_file['selected'] else "",
                zip_file['name'],
                size_str,
                zip_file['path']
            ))
            total_size += zip_file['size']
            
        # 更新统计信息
        self.total_count_var.set(f"找到压缩包: {len(self.zip_files)} 个")
        self.total_size_var.set(f"总大小: {self.format_size(total_size)}")
        
        # 绑定复选框事件
        self.tree.bind("<Button-1>", self.toggle_selection)
        
    def toggle_selection(self, event):
        region = self.tree.identify_region(event.x, event.y)
        if region == "cell":
            column = int(self.tree.identify_column(event.x).replace('#', ''))
            if column == 1:  # 第一列是选择列
                item = self.tree.identify_row(event.y)
                if item:
                    index = self.tree.index(item)
                    # 切换选择状态
                    self.zip_files[index]['selected'] = not self.zip_files[index]['selected']
                    # 更新显示
                    self.tree.set(item, 0, "✓" if self.zip_files[index]['selected'] else "")
                    
    def copy_path(self, event):
        region = self.tree.identify_region(event.x, event.y)
        if region == "cell":
            item = self.tree.identify_row(event.y)
            if item:
                index = self.tree.index(item)
                file_path = self.zip_files[index]['path']
                # 获取文件所在目录
                dir_path = os.path.dirname(file_path)
                # 复制到剪贴板
                self.root.clipboard_clear()
                self.root.clipboard_append(dir_path)
                self.log(f"已复制路径到剪贴板: {dir_path}")
                
    def format_size(self, size_bytes):
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.2f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.2f} MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.2f} GB"
            
    def log(self, message):
        """添加日志信息"""
        timestamp = time.strftime("%H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"
        
        self.root.after(0, lambda: self._update_log(log_message))
        
    def _update_log(self, message):
        self.log_text.config(state=tk.NORMAL)
        self.log_text.insert(tk.END, message)
        self.log_text.see(tk.END)
        self.log_text.config(state=tk.DISABLED)
        
    def start_extract(self):
        # 获取选中的文件
        selected_files = [f for f in self.zip_files if f['selected']]
        if not selected_files:
            messagebox.showwarning("警告", "请先选择要解压的压缩包")
            return
            
        self.extracting = True
        self.cancel_extract = False
        self.start_btn.config(state=tk.DISABLED)
        self.cancel_btn.config(state=tk.NORMAL)
        self.current_extract_index = 0
        self.total_extract_count = len(selected_files)
        self.root.after(0, lambda: self.extract_count_var.set(f"正在解压: 0/{self.total_extract_count}"))
        
        # 记录解压开始时间并启动已用时间计时器
        self.extract_start_time = time.time()
        self.start_elapsed_timer()
        
        # 在新线程中执行解压
        threading.Thread(target=self.extract_files, args=(selected_files,), daemon=True).start()
        
    def cancel_extraction(self):
        if self.extracting:
            self.cancel_extract = True
            self.log("正在取消解压操作...")
            
    def extract_files(self, files):
        total_files = len(files)
        total_size = sum(f['size'] for f in files)
        extracted_size = 0
        success_count = 0
        fail_count = 0
        fail_files = []
        start_time = time.time()
        
        self.root.after(0, lambda: self.progress_var.set(0))
        
        for i, file_info in enumerate(files):
            if self.cancel_extract:
                self.log("解压操作已取消")
                break
                
            # 更新当前解压计数
            self.current_extract_index = i + 1
            self.root.after(0, lambda: self.extract_count_var.set(
                f"正在解压: {self.current_extract_index}/{self.total_extract_count}"
            ))
                
            file_path = file_info['path']
            file_name = file_info['name']
            file_size = file_info['size']
            
            self.log(f"开始解压 {i+1}/{total_files}: {file_name} ({self.format_size(file_size)})")
            #self.root.after(0, lambda: self.progress_text_var.set(f"正在解压: {file_path}"))
            self.root.after(0, lambda: self.progress_text_var.set(
                f"正在解压: {file_path[:15] + '...' if len(file_path) > 15 else file_path}"
            ))
            
            start_file_time = time.time()
            success = False
            
            try:
                # 确定解压目录
                extract_dir = self._determine_extract_dir(file_path)
                os.makedirs(extract_dir, exist_ok=True)
                
                # 执行解压
                if file_path.lower().endswith('.zip'):
                    success = self._extract_zip(file_path, extract_dir)
                elif file_path.lower().endswith('.7z'):
                    success = self._extract_7z(file_path, extract_dir)
                elif file_path.lower().endswith('.rar'):
                    success = self._extract_rar(file_path, extract_dir)
                    
                # 解压成功
                if success:
                    success_count += 1
                    extracted_size += file_size
                    
                    # 删除原文件
                    if self.delete_after_var.get():
                        try:
                            os.remove(file_path)
                            self.log(f"已删除原压缩包: {file_name}")
                        except Exception as e:
                            self.log(f"删除原压缩包失败: {str(e)}")
                            
                # 计算单个文件解压时间
                file_time = time.time() - start_file_time
                self.log(f"解压 {file_name} 完成，耗时: {self.format_time(file_time)}")
                
            except Exception as e:
                fail_count += 1
                fail_files.append(file_path)
                self.log(f"解压 {file_name} 失败: {str(e)}")
                
                # 如果不跳过错误，就停止解压
                if not self.skip_errors_var.get():
                    self.log("遇到错误，已停止解压操作")
                    break
            
            # 更新进度
            progress = (i + 1) / total_files * 100
            self.root.after(0, lambda p=progress: self.progress_var.set(p))
            
            # 计算速度和剩余时间
            current_time = time.time()
            elapsed_time = current_time - start_time
            if elapsed_time > 0:
                speed = extracted_size / elapsed_time / (1024 * 1024)  # MB/s
                self.root.after(0, lambda s=speed: self.speed_var.set(f"速度: {s:.2f} MB/s"))
                
                # 估计剩余时间
                remaining_files = total_files - (i + 1)
                if i > 0:
                    avg_time_per_file = elapsed_time / (i + 1)
                    eta = avg_time_per_file * remaining_files
                    self.root.after(0, lambda e=eta: self.eta_var.set(f"剩余时间: {self.format_time(e)}"))
        
        # 解压完成，停止已用时间计时器
        self.elapsed_timer_running = False
        
        # 解压完成后的其他状态更新
        self.extracting = False
        self.root.after(0, lambda: self.start_btn.config(state=tk.NORMAL))
        self.root.after(0, lambda: self.cancel_btn.config(state=tk.DISABLED))
        self.root.after(0, lambda: self.progress_text_var.set("解压完成"))
        self.root.after(0, lambda: self.speed_var.set("速度: -- MB/s"))
        self.root.after(0, lambda: self.eta_var.set("剩余时间: --:--:--"))
        
        total_time = time.time() - start_time
        self.log("\n===== 解压汇总 =====")
        self.log(f"总耗时: {self.format_time(total_time)}")
        self.log(f"成功解压: {success_count} 个文件")
        self.log(f"解压失败: {fail_count} 个文件")
        self.log(f"总解压大小: {self.format_size(extracted_size)}")
        
        if fail_files:
            self.log("\n解压失败的文件:")
            for file in fail_files:
                self.log(f"- {file}")
                
    def _determine_extract_dir(self, file_path):
        """确定解压目录"""
        dir_name = os.path.dirname(file_path)
        base_name = os.path.splitext(os.path.basename(file_path))[0]
        
        # 先解压到缓存目录查看内容
        temp_dir = os.path.join(self.cache_dir, base_name)
        os.makedirs(temp_dir, exist_ok=True)
        
        try:
            # 查看压缩包内的内容
            if file_path.lower().endswith('.zip'):
                with zipfile.ZipFile(file_path, 'r') as zip_ref:
                    contents = zip_ref.namelist()
            elif file_path.lower().endswith('.7z'):
                with py7zr.SevenZipFile(file_path, 'r') as seven_ref:
                    contents = seven_ref.getnames()
            elif file_path.lower().endswith('.rar'):
                with rarfile.RarFile(file_path, 'r') as rar_ref:
                    contents = rar_ref.namelist()
            else:
                return os.path.join(dir_name, base_name)
                
            # 分析内容
            if len(contents) == 0:
                return os.path.join(dir_name, base_name)
                
            # 检查是否所有文件都在同一个根目录下
            root_dirs = set()
            for item in contents:
                parts = item.split('/')
                if len(parts) > 0 and parts[0]:
                    root_dirs.add(parts[0])
                    
            if len(root_dirs) == 1:
                # 所有文件都在同一个目录下，直接解压到当前目录
                return dir_name
            else:
                # 多个根目录或文件，创建以压缩包命名的目录
                return os.path.join(dir_name, base_name)
                
        except Exception as e:
            self.log(f"分析压缩包内容时出错: {str(e)}，将使用默认目录")
            return os.path.join(dir_name, base_name)
        finally:
            # 清理缓存目录
            if os.path.exists(temp_dir):
                try:
                    shutil.rmtree(temp_dir)
                except Exception as e:
                    self.log(f"清理缓存目录失败: {str(e)}")
                    
    def _extract_zip(self, file_path, extract_dir):
        """改进的ZIP解压函数，增强中文编码支持和错误处理"""
        try:
            with zipfile.ZipFile(file_path, 'r') as zip_ref:
                # 处理中文名编码问题
                for file_info in zip_ref.infolist():
                    original_name = file_info.filename
                    decoded = False
                    
                    # 尝试多种编码方式解码
                    for encoding in ['utf-8', 'gbk', 'gb2312', 'cp936']:
                        try:
                            file_info.filename = original_name.encode('cp437').decode(encoding)
                            decoded = True
                            break
                        except UnicodeDecodeError:
                            continue
                    
                    # 如果所有编码都尝试失败，使用原始文件名
                    if not decoded:
                        try:
                            # 尝试直接解码
                            file_info.filename = original_name
                        except:
                            # 作为最后的手段，替换无法解码的字符
                            file_info.filename = original_name.encode('utf-8', errors='replace').decode('utf-8')
                
                # 提取所有文件
                zip_ref.extractall(extract_dir)
            return True
        except KeyError as e:
            self.log(f"ZIP文件中不存在文件: {str(e)}")
            # 尝试跳过错误文件继续解压
            if self.skip_errors_var.get():
                self.log("将尝试跳过错误文件，继续解压其他文件")
                # 重新打开ZIP文件并尝试跳过错误文件
                with zipfile.ZipFile(file_path, 'r') as zip_ref:
                    return self._extract_zip_skip_error(zip_ref, extract_dir, str(e).strip("'"))
            return False
        except Exception as e:
            self.log(f"ZIP解压错误: {str(e)}")
            return False
    
    def _extract_zip_skip_error(self, zip_ref, extract_dir, error_file):
        """跳过错误文件，继续解压其他文件"""
        try:
            error_count = 0
            for file_info in zip_ref.infolist():
                # 处理文件名编码
                original_name = file_info.filename
                for encoding in ['utf-8', 'gbk', 'gb2312', 'cp936']:
                    try:
                        file_info.filename = original_name.encode('cp437').decode(encoding)
                        break
                    except UnicodeDecodeError:
                        continue
                
                # 检查是否是错误文件
                if file_info.filename == error_file or original_name == error_file:
                    error_count += 1
                    self.log(f"已跳过错误文件: {file_info.filename}")
                    continue
                
                # 解压文件
                try:
                    zip_ref.extract(file_info, extract_dir)
                except Exception as e:
                    error_count += 1
                    self.log(f"解压文件 {file_info.filename} 失败: {str(e)}")
                    if not self.skip_errors_var.get():
                        return False
            
            self.log(f"共跳过 {error_count} 个错误文件")
            return True
        except Exception as e:
            self.log(f"跳过错误文件后仍发生错误: {str(e)}")
            return False
            
    def _extract_7z(self, file_path, extract_dir):
        try:
            with py7zr.SevenZipFile(file_path, 'r') as seven_ref:
                seven_ref.extractall(extract_dir)
            return True
        except Exception as e:
            self.log(f"7Z解压错误: {str(e)}")
            return False
            
    def _extract_rar(self, file_path, extract_dir):
        try:
            with rarfile.RarFile(file_path, 'r') as rar_ref:
                rar_ref.extractall(extract_dir)
            return True
        except Exception as e:
            self.log(f"RAR解压错误: {str(e)}")
            return False
            
    def format_time(self, seconds):
        """格式化时间（秒）为 HH:MM:SS 格式"""
        hours, remainder = divmod(int(seconds), 3600)
        minutes, seconds = divmod(remainder, 60)
        return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        
    def set_timer(self):
        timer_str = self.timer_var.get()
        try:
            hours, minutes, seconds = map(int, timer_str.split(':'))
            total_seconds = hours * 3600 + minutes * 60 + seconds
            
            if total_seconds <= 0:
                messagebox.showwarning("警告", "请设置有效的时间")
                return
                
            self.remaining_time = total_seconds
            self.timer_running = True
            self.set_timer_btn.config(state=tk.DISABLED)
            self.cancel_timer_btn.config(state=tk.NORMAL)
            
            self.log(f"已设置定时任务，将在 {self.format_time(total_seconds)} 后开始解压")
            
            # 启动定时线程
            self.timer_thread = threading.Thread(target=self.run_timer, daemon=True)
            self.timer_thread.start()
            
        except ValueError:
            messagebox.showerror("错误", "时间格式不正确，请使用 HH:MM:SS 格式")
            
    def run_timer(self):
        while self.remaining_time > 0 and self.timer_running:
            self.root.after(0, lambda: self.timer_display_var.set(
                f"定时状态: 倒计时 {self.format_time(self.remaining_time)}"
            ))
            time.sleep(1)
            self.remaining_time -= 1
            
        if self.timer_running:
            # 定时结束，开始解压
            self.root.after(0, lambda: self.timer_display_var.set("定时状态: 时间到，开始解压"))
            self.root.after(0, self.start_extract)
            self.root.after(0, lambda: self.set_timer_btn.config(state=tk.NORMAL))
            self.root.after(0, lambda: self.cancel_timer_btn.config(state=tk.DISABLED))
            self.timer_running = False
            
    def cancel_timer(self):
        if self.timer_running:
            self.timer_running = False
            self.set_timer_btn.config(state=tk.NORMAL)
            self.cancel_timer_btn.config(state=tk.DISABLED)
            self.timer_display_var.set("定时状态: 已取消")
            self.log("已取消定时任务")

if __name__ == "__main__":
    root = tk.Tk()
    app = UnzipTool(root)
    root.mainloop()
